#include <PositionPredictor.h>

class CGameWorld;
class EntityMaterialInstance;
enum EGameWorldEventID;

namespace Ogre
{
    class Entity;
    class SceneNode;
}


class CShipData
{
public:
    CShipData(EShipType eShipType);
    EShipType GetShipType() const { return m_eShipType; }

    DWORD GetTorpSpeed() const { return m_dwTorpSpeed; }
    DWORD GetMaxSpeed() const { return m_dwMaxSpeed; }
    DWORD GetMaxArmies() const { return m_wMaxArmies; }
    DWORD GetMaxFuel() const { return m_dwMaxFuel; }
    DWORD GetMaxDamage() const { return m_dwMaxDamage; }
    DWORD GetMaxShield() const { return m_dwMaxShield; }
    DWORD GetMaxEngineTemp() const { return m_dwMaxEngineTemp; }
    DWORD GetMaxWeaponTemp() const { return m_dwMaxWeaponTemp; }
private:
    WORD m_wPhaserDamage;
    DWORD m_dwMaxSpeed;
    DWORD m_dwMaxFuel;
    DWORD m_dwMaxShield;
    DWORD m_dwMaxDamage;
    DWORD m_dwMaxEngineTemp;
    DWORD m_dwMaxWeaponTemp;
    WORD  m_wMaxArmies;
    WORD  m_wWidth;
    WORD  m_wHeight;
    EShipType m_eShipType;
    DWORD m_dwTorpSpeed;
};


struct mask_spacket;
// Galaxy status
class CGalaxyStatus
{
public:
    CGalaxyStatus(CGameWorld* pGameWorld);

    DWORD GetValidTeamMask() const { return m_dwValidTeamMask; }

    void HandleValidTeamMask(const mask_spacket* pPacket);

private:
    CGameWorld* m_pGameWorld;

    DWORD m_dwValidTeamMask;
    bool m_fInTournamentMode;
    DWORD m_dwArmiesBombed;
    DWORD m_dwPlanetsTaken;
    DWORD m_dwKills;
    DWORD m_dwLosses;
    DWORD m_dwTime;
    DWORD m_timeprod;
};


struct you_spacket;

class CGamePlayer;

class CLocalPlayer
{
public:
    CLocalPlayer(CGameWorld* pGameWorld);
    void HandleYouPacket(const you_spacket* pPacket);
    DWORD GetArmies() { return m_dwArmies; }

    DWORD GetPlayerID() const { return m_dwPlayerID; }
    DWORD GetFuel() const { return m_dwFuel; }
    DWORD GetDamage() const { return m_dwDamage; }
    DWORD GetShield() const { return m_dwShield; }
    DWORD GetEngineTemp() const { return m_dwEngineTemp; }
    DWORD GetWeaponTemp() const { return m_dwWeaponTemp; }
private:
    CGameWorld* m_pGameWorld;

    CGamePlayer* m_pPlayer;

    DWORD m_dwPlayerID;

    DWORD m_dwDamage;
    DWORD m_dwShield;
    DWORD m_dwArmies;
    DWORD m_dwFuel;
    DWORD m_dwEngineTemp;
    DWORD m_dwWeaponTemp;

    EKilledReason m_eKilledReason;
    DWORD m_playerIDKilledBy;
};

class CGamePlayer;
class CPlayerCloakHandler
{
public:
    CPlayerCloakHandler(CGamePlayer* pPlayer) : m_pPlayer(pPlayer), m_pMaterialInstance(NULL) { };
    ~CPlayerCloakHandler();
    void PlayerAlive();
    void Update(float flTimeDiff);
    void Reset();
    void SetCloakState(float flCloakState);
private:
    EntityMaterialInstance* m_pMaterialInstance;
    CGamePlayer* m_pPlayer;
    float m_flTargetCloakState;
};


class CPlayerTractorHandler
{
public:
    CPlayerTractorHandler(CGamePlayer* pPlayer, CGameWorld* pGameWorld);
    ~CPlayerTractorHandler();
    void Update(float flTimeDiff);
    void SetTarget(DWORD dwPlayerIDTarget) { m_dwPlayerIDTarget = dwPlayerIDTarget; }
private:
    CGamePlayer* m_pPlayer;
    CGameWorld* m_pGameWorld;
    Ogre::Entity* m_pTractorEntity;
    Ogre::SceneNode* m_pTractorNode;
    DWORD m_dwPlayerIDTarget;
};



struct plyr_login_spacket;
struct plyr_info_spacket;
struct kills_spacket;
struct pstatus_spacket;
struct flags_spacket;
struct player_spacket;
struct hostile_spacket;
struct stats_spacket;

class CGamePlayer
{
public:
    CGamePlayer(DWORD dwPlayerID, CGameWorld* pGameWorld);
    ~CGamePlayer();

    DWORD GetPlayerID() const { return m_dwPlayerID; }
    void FrameUpdate();

    void HandlePlayerLogin(const plyr_login_spacket* pPacket);
    void HandlePlayerInfo(const plyr_info_spacket* pPacket);
    void HandlePlayerKills(const kills_spacket* pPacket);
    void HandlePlayerStatus(const pstatus_spacket* pPacket);
    void HandlePlayerFlags(const flags_spacket* pPacket);
    void HandlePlayerLocation(const player_spacket* pPacket);
    void HandlePlayerHostilitySettings(const hostile_spacket* pPacket);
    void HandlePlayerStats(const stats_spacket* pPacket);

    DWORD GetXLocation() const { return m_dwXLocation; }
    DWORD GetYLocation() const { return m_dwYLocation; }
    EPlayerStatus GetPlayerStatus() const { return m_ePlayerStatus; }
    const char* GetPlayerName() const { return m_szName; }
    ETeamID GetTeamID() const { return m_eTeam; }

    // These flags correspond to the EPlayerFlags enum array
    DWORD GetPlayerFlags() const { return m_dwFlags; }
    const char* GetIdentifier() { return m_szIdentifier; }
    const CShipData* GetShipData() { return m_pShip; }
    DWORD GetRank() const { return m_dwRank; }
    DWORD GetSpeed() const { return m_bSpeed; }
    float GetKills() const { return m_flKills; }
    DWORD GetFlags() const { return m_dwFlags; }

    Ogre::Node* GetNode() { return m_pPlayerNode; }
    Ogre::Entity* GetEntity() { return m_pPlayerEntity; }
    float GetRenderedXLocation() const;
    float GetRenderedYLocation() const;
    void SetTractorTarget(DWORD dwPlayerID) { m_playerTractorHandler.SetTarget(dwPlayerID); }
    void BeginTractor();
    void EndTractor();

private:
    void CreatePlayerEntity();
    void DestroyPlayerEntity();
    void SendPlayerEvent(EGameWorldEventID eGameWorldEventID);

    CGameWorld* m_pGameWorld;

    float m_flMaxKills;
    float m_flKills;
    DWORD m_dwTicks;

    /* Stats section */
    DWORD m_dwLosses;
    DWORD m_dwArmiesBombed;
    DWORD m_dwPlanetsTaken;
    DWORD m_dwTournamentKills;
    DWORD m_dwTournamentLosses;
    DWORD m_dwTournamentArmiesBombed;
    DWORD m_dwTournamentPlanetsTaken;
    DWORD m_dwTournamentTicks;
    DWORD m_dwStarbaseKills;
    DWORD m_dwStarbaseLosses;
    float m_flStarbaseMaxKills;
    /* Stats section */

    DWORD m_dwLastLogin;
    DWORD m_dwFlags;
    DWORD m_dwRank;

    ETeamID m_eTeam;
    DWORD m_dwHostile; // Teams hostile with
    DWORD m_dwWar;     // Team at war with
    DWORD m_dwPlayerID;
    DWORD m_dwUpdatesSurvived;
    EPlayerStatus m_ePlayerStatus;
    char m_szName[16];
    char m_szLogin[16];

    const CShipData* m_pShip;
    DWORD m_dwXLocation;
    DWORD m_dwYLocation;
    BYTE  m_bHeading;
    BYTE  m_bSpeed;


    // Renderable data
    CPlayerCloakHandler m_playerCloakHandler;
    CPlayerTractorHandler m_playerTractorHandler;

    Ogre::Entity* m_pPlayerEntity;
    Ogre::SceneNode* m_pPlayerNode;

    Ogre::Entity* m_pPlayerShieldEntity;
    Ogre::SceneNode* m_pPlayerShieldNode;

    char m_szIdentifier[3];


    bool m_fFirstPositionPacket;
    float m_flTimeSinceLastUpdate;
    BYTE m_bPreviousHeading;
    DWORD m_dwPreviousXLocation;
    DWORD m_dwPreviousYLocation;
};


/* An important note concerning planets:  The game assumes that the planets
 * are in a 'known' order.  Ten planets per team, the first being the home
 * planet. */

/* the lower bits represent the original owning team */

// PLANET FLAGS
// LOWER BITS REPRESENT ORIGINAL OWNING TEAM

struct planet_loc_spacket;
struct planet_spacket;
class CPlanet
{
public:
    CPlanet(DWORD dwPlanetID, CGameWorld* pGameWorld);
    ~CPlanet();

    DWORD GetPlanetID() const { return m_dwPlanetID; }
    void FrameUpdate();
    void HandlePlanetNameAndLocation(const planet_loc_spacket* pPacket);
    void HandlePlanetResourceInfo(const planet_spacket* pPacket);

    DWORD GetFlags() const { return m_dwFlags; }
    ETeamID GetTeamOwner() const { return m_eTeamOwner; }
    DWORD GetXLocation() const { return m_dwXLocation; }
    DWORD GetYLocation() const { return m_dwYLocation; }
    const char* GetName() const { return m_szName; }
    DWORD GetArmyCount() const { return m_dwArmies; }
    DWORD GetInfoBitmask() const { return m_dwWhichTeamsHaveInfoBitfield; }
private:
    void SendPlanetEvent(EGameWorldEventID eGameWorldEventID);

    CGameWorld* m_pGameWorld;

    DWORD m_dwPlanetID;
    DWORD m_dwFlags; // These flags are defined just above.
    ETeamID m_eTeamOwner;
    DWORD m_dwXLocation;
    DWORD m_dwYLocation;
    char m_szName[16];
    DWORD m_dwArmies;

    DWORD m_dwWhichTeamsHaveInfoBitfield;

    Ogre::Entity* m_pPlanetEntity;
    Ogre::SceneNode* m_pPlanetNode;

    float m_flRotation;
};


struct torp_info_spacket;
struct torp_spacket;
class CTorp
{

public:
    CTorp(DWORD dwTorpID, CGameWorld* pGameWorld);
    ~CTorp();

    DWORD GetTorpID() const { return m_dwTorpID; }
    void FrameUpdate();

    void HandleTorpStatus(const torp_info_spacket*);
    void HandleTorpLocation(const torp_spacket*);

    bool IsInactiveTorpStatus(ETorpStatus);
    CGamePlayer* GetOwner();
    BYTE CalculateHeading(DWORD dwNewX, DWORD dwNewY);
    DWORD GetXLocation() const { return m_dwXLocation; }
    DWORD GetYLocation() const { return m_dwYLocation; }

private:
    void SendTorpEvent(EGameWorldEventID eGameWorldEventID);

    CGameWorld* m_pGameWorld;

    ETorpStatus m_eTorpStatus;
    DWORD m_dwTorpID;
    DWORD m_dwWarBitfield;
    DWORD m_dwXLocation;
    DWORD m_dwYLocation;

    BYTE m_bHeading;
    float m_flTimeSinceLastUpdate;

    Ogre::Billboard*    m_pTorpBillboard;

    DWORD m_dwTorpSpeed;
    CPositionPredictor m_positionPredictor;
    float m_flTimeSinceZero;
};

struct plasma_info_spacket;
struct plasma_spacket;
class CPlasma
{
public:
    CPlasma(DWORD dwPlasmaID, CGameWorld* pGameWorld);

    DWORD GetPlasmaID() const { return m_dwPlasmaID; }
    void FrameUpdate();

    void HandlePlasmaStatus(const plasma_info_spacket*);
    void HandlePlasmaLocation(const plasma_spacket*);

    bool IsInactivePlasmaStatus(EPlasmaStatus);
    CGamePlayer* GetOwner();

    BYTE CalculateHeading(DWORD dwNewX, DWORD dwNewY);
private:
    void SendPlasmaEvent(EGameWorldEventID eGameWorldEventID);

    CGameWorld* m_pGameWorld;

    EPlasmaStatus m_ePlasmaStatus;
    DWORD m_dwPlasmaID;
    DWORD m_dwWarBitfield;
    DWORD m_dwXLocation;
    DWORD m_dwYLocation;

    BYTE m_bHeading;
    float m_flTimeSinceLastUpdate;

    Ogre::Billboard*    m_pPlasmaBillboard;

    DWORD m_dwPlasmaSpeed;
    CPositionPredictor m_positionPredictor;
    float m_flTimeSinceZero;

};

// TBD, what info we need here

struct phaser_spacket;
class CPhaser
{
public:
    CPhaser(DWORD dwPlasmaID, CGameWorld* pGameWorld);
    ~CPhaser();
    DWORD GetPhaserID() const { return m_dwPhaserID; }

    void FrameUpdate();

    void HandlePhaser(const phaser_spacket*);

    CGamePlayer* GetOwner();
private:
    void SendPhaserEvent(EGameWorldEventID eGameWorldEventID);

    CGameWorld* m_pGameWorld;

    EPhaserStatus m_ePhaserStatus; 
    DWORD m_dwPhaserID;

    BYTE m_bHeading;
    DWORD m_dwPlayerIDTarget;
    DWORD m_dwXLocation;
    DWORD m_dwYLocation;

    Ogre::Billboard*    m_pPhaserBillboard;

    float m_flElongateTime;
};

